<?php
/**
 * Created by PhpStorm.
 * User: guokunsheng
 * Date: 2022/4/6
 * Time: 上午11:41
 */

namespace app\astrologer\controller\v1;

use app\astrologer\controller\AstrAuth;
use app\common\cachemodel\ZlcrAstr;
use app\common\cachemodel\ZlcrAstrExercise;
use app\common\cachemodel\ZlcrAstrExerciseRecord;
use app\common\lib\Util;
use think\Db;
use think\Env;
use think\exception\DbException;
use think\response\Json;

/**
 * Class User
 * 占星师用户信息
 * @package app\astrologer\controller\v1
 */
class User extends AstrAuth
{
    /**
     * 每关 每一题 分数
     * @var array
     */
    private $questionScore = [
        1 => 10,
        2 => 20,
    ];

    /**
     * 每关 通关 分数【总分】
     * @var array
     */
    private $levelSuccessScore = [
        1 => [  // 定制报告
            1 => 350,// 答对35题第一关考试通过(ps:每题10分)
            2 => 0,
        ],
        2 => [  // 三合一问答考试
            1 => 500,// 答对54题第一关考试通过(ps:每题10分)
            2 => 0,
        ],
        3 => [  // 问答-星盘
            1 => 250,// 答对27题第一关考试通过(ps:每题10分)
            2 => 0,
        ],
        4 => [  // 问答-骰子
            1 => 250,// 答对27题第一关考试通过(ps:每题10分)
            2 => 0,
        ],
        5 => [  // 问答-塔罗
            1 => 250,// 答对27题第一关考试通过(ps:每题10分)
            2 => 0,
        ],
    ];

    /**
     * 获取考试状态
     */
    public function getAssessmentData()
    {
        $imgHost = Env::get('host.photo');
        $type = input('type/d', 0); // 0=>注册场景 1=>个人中心认证 2=>问答相关认证 3=>定制报告相关认证

        $data = [
            'msg_title' => '恭喜您注册成功',
            'msg_des' => '恭喜您成功注册占星平台，完成以下流程后即可正式入驻占星平台',
            'list' => []
        ];
        $is_pass_all = true;//是否通过了所有考试

        $authStatus = $this->astrInfo['auth_status'];
        $astrAnswerModel = new ZlcrAstrExerciseRecord();
        if (in_array($type, [0, 1, 2], true))
        {
            if ($authStatus['question_answer_astr'] === 0)
            {   // 获取用户当前答题状态信息
                $astrAnswerInfo = $astrAnswerModel->getExerciseInfo($this->astrInfo['id'], 3);   // 1=>定制报告 2=>问答三合一 3=>问答星盘 4=>问答骰子 5=>问答塔罗
                if ($astrAnswerInfo && (int)$astrAnswerInfo['status'] === 2 && $this->request->time() - $astrAnswerInfo['fail_time'] > 86400)
                {
                    $astrAnswerInfo = null; // 失败24小时后允许重新考试
                }
                $res = $astrAnswerModel->getExerciseRes($astrAnswerInfo);

                $questionAnswerAstrStatus = $res[1]['status'];  // 考试状态 // -1=>不可以考试（前端不可点击）、0=>可以考试（前端可以点击）、1=>未通过、2=>已通过、3=》审核中
                $questionAnswerAstrTips = $res[1]['tips'];
                $is_pass_all = false;
            }
            if ($authStatus['question_answer_dice'] === 0)
            {   // 获取用户当前答题状态信息
                $astrAnswerInfo = $astrAnswerModel->getExerciseInfo($this->astrInfo['id'], 4);   // 1=>定制报告 2=>问答三合一 3=>问答星盘 4=>问答骰子 5=>问答塔罗
                if ($astrAnswerInfo && (int)$astrAnswerInfo['status'] === 2 && $this->request->time() - $astrAnswerInfo['fail_time'] > 86400)
                {
                    $astrAnswerInfo = null; // 失败24小时后允许重新考试
                }
                $res = $astrAnswerModel->getExerciseRes($astrAnswerInfo);

                $questionAnswerDiceStatus = $res[1]['status'];  // 考试状态
                $questionAnswerDiceTips = $res[1]['tips'];  //
                $is_pass_all = false;
            }
            if ($authStatus['question_answer_tarot'] === 0)
            {   // 获取用户当前答题状态信息
                $astrAnswerInfo = $astrAnswerModel->getExerciseInfo($this->astrInfo['id'], 5);   // 1=>定制报告 2=>问答三合一 3=>问答星盘 4=>问答骰子 5=>问答塔罗
                if ($astrAnswerInfo && (int)$astrAnswerInfo['status'] === 2 && $this->request->time() - $astrAnswerInfo['fail_time'] > 86400)
                {
                    $astrAnswerInfo = null; // 失败24小时后允许重新考试
                }
                $res = $astrAnswerModel->getExerciseRes($astrAnswerInfo);
                $questionAnswerTarotStatus = $res[1]['status']; // 考试状态
                $questionAnswerTarotTips = $res[1]['tips']; //
                $is_pass_all = false;
            }

            $questionAnswerMergeIsPassed = $authStatus['question_answer_astr'] === 1 && $authStatus['question_answer_dice'] === 1 && $authStatus['question_answer_tarot'] === 1 ? 1 : 0;
            if ($questionAnswerMergeIsPassed === 0)
            {
                $astrAnswerInfo = $astrAnswerModel->getExerciseInfo($this->astrInfo['id'], 2);   // 1=>定制报告 2=>问答三合一 3=>问答星盘 4=>问答骰子 5=>问答塔罗
                if ($astrAnswerInfo && (int)$astrAnswerInfo['status'] === 2 && $this->request->time() - $astrAnswerInfo['fail_time'] > 86400)
                {
                    $astrAnswerInfo = null; // 失败24小时后允许重新考试
                }
                $res = $astrAnswerModel->getExerciseRes($astrAnswerInfo);
                $questionAnswerMergeStatus = $res[1]['status']; // 考试状态
                $questionAnswerMergeTips = $res[1]['tips']; //
            }

            $data['list'][] = [
                'title' => '问答技能考核',
                'list' => [
                    [
                        'type' => 2,
                        'img' => $imgHost . '/mini/astrologer/test/1.png',
                        'name' => '3合1综合技能测试',
                        'desc' => '您需要熟练掌握星盘、占星骰子、塔罗的相关知识，能独立输出自己的观点。',
                        'tips' => '通过后可获得所有问答的接单资格',
                        'is_passed' => $questionAnswerMergeIsPassed,
                        'list' => [
                            [
                                'id' => 1,
                                'title' => '选择题',
                                'status' => $questionAnswerMergeStatus ?? 2,  // 考试状态 // -1=>不可以考试（前端不可点击）、0=>可以考试（前端可以点击）、1=>未通过、2=>已通过、3=》审核中
                                'tips' => $questionAnswerMergeTips ?? '',
                                'content' => [
                                    '每个人每类测评每天只有1次测评机会，未通过则24小时后重试。',
                                    '考试限时60分钟内完成，如果测试中途退出，结果保留，可继续进行测试。',
                                    '共60道题，答对50道题通过考试，每道题限时1分钟内完成，超时自动判错。',
                                ],
                            ],
                        ],
                    ],
                    [
                        'type' => 3,
                        'img' => $imgHost . '/mini/astrologer/test/2.png',
                        'name' => '咨询师测评-星盘问答',
                        'desc' => '您需要熟练掌握星盘相关知识，能独立输出自己的观点。',
                        'tips' => '通过后可获得星盘问答的接单资格',
                        'is_passed' => $authStatus['question_answer_astr'] === 1 ? 1 : 0,
                        'list' => [
                            [
                                'id' => 1,
                                'title' => '选择题',
                                'status' => $questionAnswerAstrStatus ?? 2, // 考试状态 // -1=>不可以考试（前端不可点击）、0=>可以考试（前端可以点击）、1=>未通过、2=>已通过、3=》审核中
                                'tips' => $questionAnswerAstrTips ?? '',
                                'content' => [
                                    '每个人每类测评每天只有1次测评机会，未通过则24小时后重试。',
                                    '考试限时40分钟内完成，如果测试中途退出，结果保留，可继续进行测试。',
                                    '共30道题，答对25道题通过考试，每道题限时1分钟内完成，超时自动判错。',
                                ],
                            ],
                        ],
                    ],
                    [
                        'type' => 4,
                        'img' => $imgHost . '/mini/astrologer/test/3.png',
                        'name' => '咨询师测评-骰子问答',
                        'desc' => '您需要熟练掌握占星骰子相关知识，能独立输出自己的观点。',
                        'tips' => '通过后可获得骰子问答的接单资格',
                        'is_passed' => $authStatus['question_answer_dice'] === 1 ? 1 : 0,
                        'list' => [
                            [
                                'id' => 1,
                                'title' => '选择题',
                                'status' => $questionAnswerDiceStatus ?? 2,// 考试状态 // -1=>不可以考试（前端不可点击）、0=>可以考试（前端可以点击）、1=>未通过、2=>已通过、3=》审核中
                                'tips' => $questionAnswerDiceTips ?? '',
                                'content' => [
                                    '每个人每类测评每天只有1次测评机会，未通过则24小时后重试。',
                                    '考试限时40分钟内完成，如果测试中途退出，结果保留，可继续进行测试。',
                                    '共30道题，答对25道题通过考试，每道题限时1分钟内完成，超时自动判错。',
                                ],
                            ],
                        ],
                    ],
                    [
                        'type' => 5,
                        'img' => $imgHost . '/mini/astrologer/test/4.png',
                        'name' => '咨询师测评-塔罗问答',
                        'desc' => '您需要熟练掌握塔罗相关知识，能独立输出自己的观点。',
                        'tips' => '通过后可获得塔罗问答的接单资格',
                        'is_passed' => $authStatus['question_answer_tarot'] === 1 ? 1 : 0,
                        'list' => [
                            [
                                'id' => 1,
                                'title' => '选择题',
                                'status' => $questionAnswerTarotStatus ?? 2,// 考试状态 // -1=>不可以考试（前端不可点击）、0=>可以考试（前端可以点击）、1=>未通过、2=>已通过、3=》审核中
                                'tips' => $questionAnswerTarotTips ?? '',
                                'content' => [
                                    '每个人每类测评每天只有1次测评机会，未通过则24小时后重试。',
                                    '考试限时40分钟内完成，如果测试中途退出，结果保留，可继续进行测试。',
                                    '共30道题，答对25道题通过考试，每道题限时1分钟内完成，超时自动判错。',
                                ],
                            ],
                        ],
                    ],
                ]
            ];
        }

        if (in_array($type, [0, 1, 3], true))
        {
            if ($authStatus['custom_report'] === 0)
            {   // 获取用户当前答题状态信息
                $astrAnswerInfo = $astrAnswerModel->getExerciseInfo($this->astrInfo['id'], 1);   // 1=>定制报告 2=>问答三合一 3=>问答星盘 4=>问答骰子 5=>问答塔罗
                if ($astrAnswerInfo && (int)$astrAnswerInfo['status'] === 2 && $this->request->time() - $astrAnswerInfo['fail_time'] > 86400)
                {
                    $astrAnswerInfo = null; // 失败24小时后允许重新考试
                }
                $res = $astrAnswerModel->getExerciseRes($astrAnswerInfo);
                $customReport1Status = $res[1]['status']; // 考试状态
                $customReport1Tips = $res[1]['tips']; //
                $customReport2Status = $res[2]['status']; // 考试状态
                $customReport2Tips = $res[2]['tips']; //
                $is_pass_all = false;
            }

            $data['list'][] = [
                'title' => '定制报告技能测试考核',
                'list' => [
                    [
                        'type' => 1,
                        'img' => $imgHost . '/mini/astrologer/test/5.png',
                        'name' => '占星师测评-定制报告',
                        'desc' => '您需要熟练掌握星盘相关知识，能独立输出自己的观点。',
                        'tips' => '通过后获得定制报告及星盘问答接单资格',
                        'is_passed' => $authStatus['custom_report'] === 1 ? 1 : 0,
                        'list' => [
                            [
                                'id' => 1,
                                'title' => '选择题',
//                                'status' => $customReport1Status ?? 2,
//                                'tips' => $customReport1Tips ?? '',
                                'status' => -1,
                                'tips' => '系统升级中明天再试',
                                'content' => [
                                    '选择题考核共40题，分单选及多选，答对35题则考核成功进入笔试考核',
                                    '选择题考核每题回答时间为60秒，若超时则当前题默认0分，自动进入下一道题',
                                    '选择题考核总时长为1小时，若超过规定时间未提交则所有超时的题，自动设置为0分',
                                    '考核如不通过则从考试结束时间开始计算间隔24小时才可继续重新考核'
                                ],
                            ],
                            [
                                'id' => 2,
                                'title' => '简答题',
//                                'status' => $customReport2Status ?? 2,
//                                'tips' => $customReport2Tips ?? '',
                                'status' => -1,
                                'tips' => '系统升级中明天再试',
                                'content' => [
                                    '占星师开始笔试考核后需要在特定星盘下回答指定问题，回复字数以及占星技法不限',
                                    '笔试考核总计时间为4小时，点击开始笔试考核后开始计时。若超过指定时间未提交则自动设置为0分',
                                    '提交回复后请占星师耐心等待，官方审核人员快马加鞭将在7个工作日内给予短信回复通知，请留意手机短信',
                                    '通过笔试考核后则可继续登录填写资料完成后续入驻流程'
                                ],
                            ],
                        ],
                    ],
                ],
            ];
        }

        if ($type === 1)
        {//个人中心点击认证考试
            if ($is_pass_all)
            {//已通过全部考试
                $data['msg_title'] = '';
                $data['msg_des'] = '';
            } else
            {//未通过全部考试，顶部的提示
                $data['msg_title'] = '你还有未通过的考核测试';
                $data['msg_des'] = '你可以选择一下考核测试，获得相应的接单资格';
            }
        }

        return show(200, '请求成功', $data);
    }

    /**
     * 获取考试题目
     * @throws Exception
     */
    public function getExamineQuestion()
    {
        $type = input('type/d', 0); // 考试类型 1=>定制报告 2=>问答三合一 3=>问答星盘 4=>问答骰子 5=>问答塔罗
        $index = input('index/d', 0);
        $option = trim(input('option/s', ''));

        if (!in_array($type, [1, 2, 3, 4, 5], true))
        {
            return show(config('code.error'), '请求异常，请稍后再试～');
        }

        if ($type === 1 && $this->astrInfo['auth_status']['custom_report'] === 1)
        {
            return show(config('code.error'), '定制报告占星师测评已经通过了');
        }
        if ($type === 2 && $this->astrInfo['auth_status']['question_answer_astr'] === 1 && $this->astrInfo['auth_status']['question_answer_dice'] === 1 && $this->astrInfo['auth_status']['question_answer_tarot'] === 1)
        {
            return show(config('code.error'), '3合1综合技能测评已经通过了');
        }
        if ($type === 3 && $this->astrInfo['auth_status']['question_answer_astr'] === 1)
        {
            return show(config('code.error'), '星盘问答咨询师测评已经通过了');
        }
        if ($type === 4 && $this->astrInfo['auth_status']['question_answer_dice'] === 1)
        {
            return show(config('code.error'), '骰子问答咨询师测评已经通过了');
        }
        if ($type === 5 && $this->astrInfo['auth_status']['question_answer_tarot'] === 1)
        {
            return show(config('code.error'), '塔罗问答咨询师测评已经通过了');
        }

        $questionModel = new ZlcrAstrExercise();
        $astrAnswerModel = new ZlcrAstrExerciseRecord();

        // 获取用户当前答题状态信息
        $astrAnswerInfo = $astrAnswerModel->getExerciseInfo($this->astrInfo['id'], $type);

        if (Env::get('host.name') !== 'online')
        {
            $this->levelSuccessScore[$type] = [
                1 => 10,
                2 => 0,
            ];
        }

        if ($astrAnswerInfo)
        {
            $astrAnswerInfo['status'] = (int)$astrAnswerInfo['status'];
        }
        if ($astrAnswerInfo && $astrAnswerInfo['status'] === 2)
        {
            if ($this->request->time() - $astrAnswerInfo['fail_time'] > 86400)
            {
                $astrAnswerInfo = null; // 失败24小时后重新考试
                $astrAnswerModel->rmCacheData($this->astrInfo['id'], $type);
            } else
            {
                return show(config('code.error'), '当前考核已结束');
            }
        }
        // 获取当前用户答题进度
        if (!$astrAnswerInfo)
        {   // 初始化答题进度
            switch ($type)
            {
                case 1:
                    // 获取第一关 随机35题
                    $num_option_one = 35;   // 单选题目数
                    $num_option_mul = 5;    // 多选题目数
                    if (Env::get('host.name') !== 'online')
                    {
                        $num_option_one = 1;
                        $num_option_mul = 5;
                    }
                    $questionIds = $questionModel->randomGetQuestionId(1, $num_option_one, 1);
                    shuffle($questionIds);
                    $Level2QuestionIds = $questionModel->randomGetQuestionId(2, $num_option_mul, 1);
                    shuffle($Level2QuestionIds);
                    $questionIds = array_merge($questionIds, $Level2QuestionIds);

                    $questionNum = $num_option_one + $num_option_mul; // 总题目数
                    break;
                case 2:
                    $question1Ids = $questionModel->randomGetQuestionId(1, 20, 3);
                    $question2Ids = $questionModel->randomGetQuestionId(1, 20, 4);
                    $question3Ids = $questionModel->randomGetQuestionId(1, 20, 5);
                    $questionIds = array_merge($question1Ids, $question2Ids, $question3Ids);
                    shuffle($questionIds);
                    $questionNum = 60; // 总题目数
                    break;
                default:    // 3=>问答星盘 4=>问答骰子 5=>问答塔罗  考试题目数为30题
                    $questionNum = 30;
                    $questionIds = $questionModel->randomGetQuestionId(1, $questionNum, $type);
            }
            if (!$questionIds)
            {
                return show(config('code.error'), '服务异常；请稍后再试～');
            }

            $content1 = [
                'question' => $questionIds,
                'start_time' => $this->request->time(), // 开始答题时间
                'index' => 1, // 当前第几题
                'max_question' => $questionNum,  // 总题目数
                'max_answer_time' => 60, // 最大答题时长
                'answer' => [] // 答案信息
            ];

            $cacheData = [
                'create_time' => $this->request->time(),
                'astr_id' => $this->astrInfo['id'],
                'content1' => \GuzzleHttp\json_encode($content1, JSON_UNESCAPED_UNICODE),
                'type' => $type,
                'content2' => '',
                'content3' => '',
                'content4' => '',
                'grade1' => 0,
                'grade2' => 0,
                'grade3' => 0,
                'grade4' => 0,
                'grade' => 0,
                'level' => 1,
                'status' => 1,
                'answer_time' => 0, //答题耗时 总时长
                'fail_time' => 0, // 失败时间
            ];

            $astrAnswerModel->setCacheData($cacheData, $this->astrInfo['id'], $type);

            $questionId = $questionIds[$content1['index'] - 1];// 获取当前题目ID

            $resData = $this->getResultData($content1, $questionId, 10);
        } else
            switch ($astrAnswerInfo['level'])
            {
                case 1:
                    // 提交答案 ｜ 获取题目 ｜ 结果
                    $content1 = \GuzzleHttp\json_decode($astrAnswerInfo['content1'], true);
                    if ($astrAnswerInfo['status'] === 2 || (isset($content1['answer_total_time']) && $content1['answer_total_time']))
                    {
                        $resData = [
                            'step' => 11,
                            'answer_right' => $content1['answer_right_num'],
                            'answer_wrong' => $content1['answer_wrong_num'],
                            'timeout_num' => $content1['answer_timeout_num'],
                            'max_question' => $content1['max_question'],
                            'isSuccessful' => false, // 是否通关
                            'tips' => '很遗憾您未能通过考核，请24小时后再次尝试'
                        ];
                        break;
                    }
                    if ($index && $option && $index <= $content1['index'])
                    {   // 提交答案
                        $res = $this->nextQuestion($content1, $index, $option, 10);
                        if ($res['updateCache'])
                        {   // 是否更新缓存
                            $astrAnswerInfo['content1'] = \GuzzleHttp\json_encode($res['content'], JSON_UNESCAPED_UNICODE);
                            if ($res['isOver'])
                            {
                                $score = $res['content']['answer_right_num'] * $this->questionScore[1];//每题5分
                                $astrAnswerInfo['grade1'] = $score; // 第一关分数
                                $astrAnswerInfo['grade'] += $score; // 总分数
                                $astrAnswerInfo['answer_time'] += $res['content']['answer_total_time']; // 答题总时长
                                if ($astrAnswerInfo['grade1'] < $this->levelSuccessScore[$type][1]) // 总分
                                {   // 通关失败
                                    $astrAnswerInfo['status'] = 2;//挑战结束
                                    $astrAnswerInfo['fail_time'] = $this->request->time();
                                } else
                                {
                                    $astrAnswerInfo['level']++; // 升级下一关
                                }
                                unset($astrAnswerInfo['id']);
                                if (in_array($type, [2, 3, 4, 5], true) && ($astrAnswerInfo['status'] === 1))
                                {   // 考核问答相关考试
                                    $astrAnswerInfo['status'] = 3;  // 考试通过
                                    $astrAnswerModel->astrExercisePass($this->astrInfo, $type); // 更新占星师 认证状态
                                }

                                $id = $astrAnswerModel->insertGetId($astrAnswerInfo);

                                $astrAnswerInfo['id'] = $id;

                                if ($type === 1)
                                {
                                    $tips = $astrAnswerInfo['status'] === 1 ? '恭喜您通过选择题考核，完成笔试考核即可入住平台' : '很遗憾您未能通过考核，请24小时后再次尝试';
                                } else
                                {
                                    $tips = $astrAnswerInfo['status'] === 3 ? '恭喜您通过选择题考核' : '很遗憾您未能通过考核，请24小时后再次尝试';
                                }

                                $resData = [
                                    'step' => 11,
                                    'answer_right' => $res['content']['answer_right_num'],
                                    'answer_wrong' => $res['content']['answer_wrong_num'],
                                    'timeout_num' => $res['content']['answer_timeout_num'],
                                    'max_question' => $res['content']['max_question'],
                                    'isSuccessful' => $astrAnswerInfo['status'] !== 2, // 是否通关
                                    'tips' => $tips
                                ];
                                $astrAnswerModel->setCacheData($astrAnswerInfo, $this->astrInfo['id'], $type); // 更新缓存
                                //发送钉钉通知
                                Util::sendZlcrMsg(7, ['占星师ID：' . $this->astrInfo['id'], '总计:' . $resData['max_question'] . ',答对:' . $resData['answer_right'] . ',答错:' . $resData['answer_wrong']], $this->headers['app-type']);
                                break;
                            }

                            $astrAnswerModel->setCacheData($astrAnswerInfo, $this->astrInfo['id'], $type); // 更新缓存
                        }
                        $resData = $res['resData'];
                    } else
                    {   // 获取题目
                        $isNext = ($this->request->time() - $content1['start_time']) >= $content1['max_answer_time']; // 是否下一题
                        if ($isNext)
                        {   // 下一题
                            $res = $this->nextQuestion($content1, $content1['index'], '', 10);
                            if ($res['updateCache'])
                            {   // 是否更新缓存
                                $astrAnswerInfo['content1'] = \GuzzleHttp\json_encode($res['content'], JSON_UNESCAPED_UNICODE);
                                if ($res['isOver'])
                                {
                                    $score = $res['content']['answer_right_num'] * $this->questionScore[1];//每题5分
                                    $astrAnswerInfo['grade1'] = $score; // 第一关分数
                                    $astrAnswerInfo['grade'] += $score; // 总分数
                                    $astrAnswerInfo['answer_time'] += $res['content']['answer_total_time']; // 答题总时长

                                    if ($astrAnswerInfo['grade1'] < $this->levelSuccessScore[$type][1]) // 总分
                                    {   // 通关失败
                                        $astrAnswerInfo['status'] = 2;//挑战结束
                                        $astrAnswerInfo['fail_time'] = $this->request->time();
                                    } else
                                    {
                                        $astrAnswerInfo['level']++; // 升级下一关
                                    }
                                    unset($astrAnswerInfo['id']);
                                    if (in_array($type, [2, 3, 4, 5], true) && ($astrAnswerInfo['status'] === 1))
                                    {   // 考核问答相关考试
                                        $astrAnswerInfo['status'] = 3;  // 考试通过
                                        $astrAnswerModel->astrExercisePass($this->astrInfo, $type); // 更新占星师 认证状态
                                    }

                                    $id = $astrAnswerModel->insertGetId($astrAnswerInfo);

                                    $astrAnswerInfo['id'] = $id;

                                    if ($type === 1)
                                    {
                                        $tips = $astrAnswerInfo['status'] === 1 ? '恭喜您通过选择题考核，完成笔试考核即可入住平台' : '很遗憾您未能通过考核，请24小时后再次尝试';
                                    } else
                                    {
                                        $tips = $astrAnswerInfo['status'] === 3 ? '恭喜您通过选择题考核' : '很遗憾您未能通过考核，请24小时后再次尝试';
                                    }

                                    $resData = [
                                        'step' => 11,
                                        'answer_right' => $res['content']['answer_right_num'],
                                        'answer_wrong' => $res['content']['answer_wrong_num'],
                                        'timeout_num' => $res['content']['answer_timeout_num'],
                                        'max_question' => $res['content']['max_question'],
                                        'isSuccessful' => $astrAnswerInfo['status'] !== 2, // 是否通关
                                        'tips' => $tips
                                    ];
                                    $astrAnswerModel->setCacheData($astrAnswerInfo, $this->astrInfo['id'], $type); // 更新缓存
                                    //发送钉钉通知
                                    Util::sendZlcrMsg(7, ['占星师ID：' . $this->astrInfo['id'], '总计:' . $resData['max_question'] . ',答对:' . $resData['answer_right'] . ',答错:' . $resData['answer_wrong']], $this->headers['app-type']);
                                    break;
                                }

                                $astrAnswerModel->setCacheData($astrAnswerInfo, $this->astrInfo['id'], $type); // 更新缓存
                            }
                            $resData = $res['resData'];
                        } else
                        {   // 当前题
                            $resData = $this->getResultData($content1, $content1['question'][$content1['index'] - 1], 10);
                        }
                    }
                    break;
                case 2:
                    if ($astrAnswerInfo['content2'])
                    {
                        $content2 = \GuzzleHttp\json_decode($astrAnswerInfo['content2'], true);
                        if ($content2['answer'])
                        {   // 提交过答案了
                            $resData = [
                                'step' => 21,
                                "index" => 1,//当前为第几题
                                "max_question" => 1,//总共有多少题
                                "tips" => '等待审核'
                            ];
                            break;
                        }
                        if ($option)
                        {   // 回答问题
                            $answerTime = $this->request->time() - $content2['start_time'];// 答题时间

                            if ($answerTime > ($content2['max_answer_time'] + 100))
                            { // 超时100秒提交 则无效
                                $option = '';
                            }
                            $content2['answer'] = [
                                'answer_time' => $answerTime > $content2['max_answer_time'] ? $content2['max_answer_time'] : $answerTime,
                                'option' => $option,
                                'start_time' => date('Y-m-d H:i:s', $content2['start_time']),
                            ];
                            $astrAnswerInfo['content2'] = \GuzzleHttp\json_encode($content2, JSON_UNESCAPED_UNICODE);
                            $astrAnswerInfo['answer_time'] += $content2['answer']['answer_time'];
                            $astrAnswerInfo['status'] = $option ? 4 : 2;  // 4=>待审核 ｜ 2=>失败
                            $astrAnswerInfo['fail_time'] = $content2['start_time'] + $content2['max_answer_time'];
                            // 更新
                            $astrAnswerModel->where('id', $astrAnswerInfo['id'])->update([
                                'update_time' => $this->request->time(),
                                'content2' => $astrAnswerInfo['content2'],
                                'answer_time' => $astrAnswerInfo['answer_time'],
                                'fail_time' => $astrAnswerInfo['fail_time'],
                                'status' => $astrAnswerInfo['status'],
                                'level' => $astrAnswerInfo['level']
                            ]);

                            if ($astrAnswerInfo['status'] === 4)
                            {
                                if ($this->astrInfo['check_status'] < 20)
                                {
                                    (new ZlcrAstr())->UpdateData($this->astrInfo['id'], ['id' => $this->astrInfo['id']], ['check_status' => 11]);
                                }
                            }

                            $resData = [
                                'step' => 21,
                                "index" => 1,//当前为第几题
                                "max_question" => 1,//总共有多少题
                                "tips" => $astrAnswerInfo['status'] === 2 ? '很遗憾您未能通过考核，请24小时后再次尝试' : '等待审核'
                            ];

                            $astrAnswerModel->setCacheData($astrAnswerInfo, $this->astrInfo['id'], $type); // 更新缓存

                            //发送钉钉通知
                            Util::sendZlcrMsg(1, ['请尽快审核'], $this->headers['app-type']);
                            break;
                        }

                        // 获取问题
                        $isNext = ($this->request->time() - $content2['start_time']) >= $content2['max_answer_time']; // 是否下一题
                        if ($isNext)
                        {
                            $content2['answer'] = [
                                'answer_time' => $content2['max_answer_time'],
                                'option' => '',
                                'start_time' => date('Y-m-d H:i:s', $content2['start_time']),
                            ];
                            $astrAnswerInfo['content2'] = \GuzzleHttp\json_encode($content2, JSON_UNESCAPED_UNICODE);
                            $astrAnswerInfo['answer_time'] += $content2['max_answer_time'];
                            $astrAnswerInfo['status'] = 2;
                            $astrAnswerInfo['fail_time'] = $content2['start_time'] + $content2['max_answer_time'];
                            // 更新
                            $astrAnswerModel->where('id', $astrAnswerInfo['id'])->update([
                                'update_time' => $this->request->time(),
                                'content2' => $astrAnswerInfo['content2'],
                                'answer_time' => $astrAnswerInfo['answer_time'],
                                'fail_time' => $astrAnswerInfo['fail_time'],
                                'status' => $astrAnswerInfo['status'],
                                'level' => $astrAnswerInfo['level']
                            ]);
                            $astrAnswerModel->setCacheData($astrAnswerInfo, $this->astrInfo['id'], $type); // 更新缓存

                            $resData = [
                                'step' => 21,
                                "index" => 1,//当前为第几题
                                "max_question" => 1,//总共有多少题
                                "tips" => '很遗憾您未能通过考核，请24小时后再次尝试'
                            ];
                            break;
                        }
                        $resData = $this->getResultData($content2, $content2['question'][$content2['index'] - 1], 20);
                    } else
                    {
                        if ($astrAnswerInfo['status'] === 2 || $astrAnswerInfo['grade1'] < $this->levelSuccessScore[$type][1]) // 当前关卡分数满足条件
                        {
                            return show(config('code.error'), '当前考核已结束');
                        }
                        // 初始化第二关答题进度
                        // 获取第二关 随机1题
                        $questionIds = $questionModel->randomGetQuestionId(3, 1, 1);

                        if (!$questionIds)
                        {
                            return show(config('code.error'), '服务异常；请稍后再试～');
                        }

                        $content2 = [
                            'question' => $questionIds,
                            'start_time' => $this->request->time(), // 开始答题时间
                            'index' => 1, // 当前第几题
                            'max_question' => 1,  // 总题目数
                            'max_answer_time' => 14400, // 最大答题时长 4小时
                            'answer' => [] // 答案信息
                        ];
                        $questionId = $questionIds[$content2['index'] - 1];// 获取当前题目ID

                        $astrAnswerInfo['content2'] = \GuzzleHttp\json_encode($content2, JSON_UNESCAPED_UNICODE);
                        $astrAnswerModel->setCacheData($astrAnswerInfo, $this->astrInfo['id'], $type); // 更新缓存

                        $resData = $this->getResultData($content2, $questionId, 20);
                    }
                    break;
                default:
                    return show(config('code.error'), '服务异常；请稍后再试～');
            }

        // 返回结果
        return show(config('code.success'), '请求成功', $resData);
    }

    /**
     * 返回题目信息
     * @param $content array 问题信息
     * @param $qid int  问题ID
     * @param $step int 当前进度 10=>第一关进行中 20=>第二关进行中 30=>第三关进行中 40=>第四关进行中
     * @return array
     * @throws Exception
     */
    private function getResultData(array $content, int $qid, int $step): array
    {
        $questionInfo = (new ZlcrAstrExercise())->getInfoById($qid, ['title', 'option_a', 'option_b', 'option_c', 'option_d', 'title_img', 'option_type']);

        $endTime = $content['max_answer_time'] ? $content['max_answer_time'] - ($this->request->time() - $content['start_time']) : 0;
        $tips = '';
        if ((int)$questionInfo['option_type'] === 3)
        {
//            $times = $this->request->time() + $endTime;
//            $tips = date('Y.m.d H:i:s', $times);
            $tips = '等待审核';
            $astro = [
                'is_merage' => false,
                'id' => $qid
            ];
        } else
        {
            $topicOption = [
                [
                    'text' => htmlspecialchars_decode($questionInfo['option_a']),
                    'value' => 'A'
                ],
                [
                    'text' => htmlspecialchars_decode($questionInfo['option_b']),
                    'value' => 'B'
                ],
                [
                    'text' => htmlspecialchars_decode($questionInfo['option_c']),
                    'value' => 'C'
                ],
                [
                    'text' => htmlspecialchars_decode($questionInfo['option_d']),
                    'value' => 'D'
                ]
            ];
        }

        return [
            'step' => $step,
            'index' => (int)$content['index'],
            'max_question' => (int)$content['max_question'],
            'end_time' => $endTime,
            'title' => htmlspecialchars_decode($questionInfo['title']),
            'topic_option' => $topicOption ?? null,
            'astro' => $astro ?? null,
            'option_type' => (int)$questionInfo['option_type'],
            'title_img' => $questionInfo['title_img'] ? Env::get('host.photo') . $questionInfo['title_img'] : '',
            'tips' => $tips
        ];
    }

    /**
     * 提交答案 进入下一题 ｜ 计算结果
     * @param $content array 关卡内容
     * @param $index int  当前题目
     * @param $option string 答案
     * @param $setp int 当前进度 10=>第一关进行中 20=>第二关进行中 30=>第三关进行中 40=>第四关进行中
     * @return array
     * @throws Exception
     */
    private function nextQuestion(array $content, int $index, string $option, int $setp): array
    {
        if ($index < $content['index'])
        {  // 可能情况  网络异常或其他 回答上一题答案
            $updateCache = false;
            if ($index === ($content['index'] - 1) && (($answerTime = $this->request->time() - strtotime($content['answer'][$index]['start_time'])) < ($content['max_answer_time'] + 10)))
            { // 在上一题允许范围内 则 为有效答题
                $content['answer'][$index] = [
                    'answer_time' => $answerTime > $content['max_answer_time'] ? $content['max_answer_time'] : $answerTime, // 当前问题消耗时长
                    'option' => $option, // 答案
                    'start_time' => $content['answer'][$index]['start_time']
                ];
            } else
            { // 无效答题
                if ($content['max_answer_time'] > 0 && ($this->request->time() - $content['start_time']) >= $content['max_answer_time'])
                { // 当前答案回答时间 也过期
                    $content['answer'][$content['index']] = [
                        'answer_time' => $content['max_answer_time'], // 当前问题消耗时长
                        'option' => '', // 答案
                        'start_time' => date('Y-m-d H:i:s', $content['start_time'])
                    ];
                    $content['index']++;
                    $updateCache = true;
                    if ($content['index'] > $content['max_question'])
                    { // 计算结果 | 返回答题信息
                        // 计算答题信息
                        $content = $this->totalScore($content);
                        return [
                            'content' => $content,
                            'updateCache' => true,
                            'isOver' => true,
                        ];
                    }
                    $content['start_time'] = $this->request->time();
                }
            }

            return [
                'content' => $content,
                'updateCache' => $updateCache,
                'isOver' => false,
                'resData' => $this->getResultData($content, $content['question'][$content['index'] - 1], $setp)
            ];
        }

        // 正常提交答案
        $answerTime = $this->request->time() - $content['start_time'];
        if ($content['max_answer_time'] > 0 && (!$option || ($answerTime > ($content['max_answer_time'] + 10))))
        {   // 无效答题
            $option = '';
        }
        $content['answer'][$index] = [
            'answer_time' => $answerTime > $content['max_answer_time'] ? $content['max_answer_time'] : $answerTime, // 当前问题消耗时长
            'option' => $option, // 答案
            'start_time' => date('Y-m-d H:i:s', $content['start_time'])
        ];

        if ($content['index'] >= $content['max_question'])
        { // 计算结果 得分
            // 计算答题信息
            $content = $this->totalScore($content);
            return [
                'content' => $content,
                'updateCache' => true,
                'isOver' => true,
            ];
        }

        // 返回下一题
        $content['index']++;
        $content['start_time'] = $this->request->time();
        return [
            'content' => $content,
            'updateCache' => true,
            'isOver' => false,
            'resData' => $this->getResultData($content, $content['question'][$content['index'] - 1], $setp)
        ];
    }

    /**
     * 计算正确结果
     * @param $content
     * @return array
     * @throws Exception
     */
    private function totalScore(array $content): array
    {
        $questionInfo = (new ZlcrAstrExercise())->batchGetInfoByIds($content['question'], ['answer', 'option_type']);

        $answerTotalTime = 0; // 答题总时长
        $answerRight = 0;// 正确答题数
        $timeOutNum = 0;// 超时数量
        $answerWrong = 0;// 错误答题数
        $answerRightQuestion = [];// 回答正确的题目 第几题 题目从1开始
        for ($i = 1; $i <= $content['max_question']; $i++)
        {
            if (isset($content['answer'][$i]) && $content['answer'][$i]['option'])
            {   // 如果当前题目回答了
                // 判断是否正确
                if ($questionInfo[$content['question'][$i - 1]]['option_type'] == 1)
                {
                    $answer = strtoupper($content['answer'][$i]['option']);
                    $questionAnswer = strtoupper(trim($questionInfo[$content['question'][$i - 1]]['answer'])); // 问题答案
                } else
                {
                    $answer = explode(',', strtoupper($content['answer'][$i]['option'])); // 答案
                    $questionAnswer = explode(',', strtoupper(trim($questionInfo[$content['question'][$i - 1]]['answer']))); // 问题答案
                    asort($answer);
                    asort($questionAnswer);
                    $answer = array_values($answer);
                    $questionAnswer = array_values($questionAnswer);
                }
                if ($answer === $questionAnswer)
                {
                    $answerRight++;
                    $answerRightQuestion[] = $i;// 当前第几题回答正确
                } else
                {
                    $answerWrong++;
                }
                $answerTotalTime += $content['answer'][$i]['answer_time'];//答题时长
            } else
            {   // 当前题目超时未回答
                $timeOutNum++;
                $answerTotalTime += $content['max_answer_time']; // 答题时长
            }
        }

        $content['answer_total_time'] = $answerTotalTime; // 答题总时长
        $content['answer_right_num'] = $answerRight;    // 答对的题目数量
        $content['answer_timeout_num'] = $timeOutNum;    // 超时数量
        $content['answer_wrong_num'] = $answerWrong;    // 错误答题数
        $content['answer_right_question'] = $answerRightQuestion; // 答对的题目

        return $content;
    }

    /**
     * 获取咨询师等级信息
     */
    public function getUserLevelInfo()
    {
        $apiHost = Env::get('host.domain');
        $imgHost = Env::get('host.photo');
        $nowTime = time();
        $astrModel = new ZlcrAstr();

        $authStatus = $this->astrInfo['auth_status'];
        $data = [];
        $hint = '';//顶部提示

        if ($authStatus['custom_report'] === 1)
        {   // 定制报告
            $astrLevel = abs($this->astrInfo['astr_level']);
            $data[] = [
                'type' => 1,
                'title' => '定制报告能力分',
                'img' => $imgHost . '/mini/astrologer/test/1.png',
                'grade' => $this->astrInfo['astro_grade'],
                'level_name' => $astrModel->astrLevelName2[1][$astrLevel],
                'proportion' => ($astrModel->astrLevelProportion[$astrLevel] * 100) . '%',
                'protocol_url' => $apiHost . '/web/rule_astrologer',
            ];
        } else
        {
            $hint = '定制报告';
        }

        if ($authStatus['question_answer_astr'] === 1)
        {   // 问答星盘
            $astro2Level = abs($this->astrInfo['astro2_level']);
            $data[] = [
                'type' => 2,
                'title' => '问答-占星能力分',
                'img' => $imgHost . '/mini/astrologer/test/1.png',
                'grade' => $this->astrInfo['astro2_grade'],
                'level_name' => $astrModel->astrLevelName2[2][$astro2Level],
                'proportion' => ($astrModel->getAstrQuestionAnswerProportion($nowTime, 1, $astro2Level) * 100) . '%',
                'protocol_url' => $apiHost . '/web/rule_astro_grade',
            ];
        } else
        {
            if ($hint)
            {
                $hint .= '、';
            }
            $hint .= '问答星盘';
        }

        if ($authStatus['question_answer_tarot'] === 1)
        {   // 问答塔罗
            $tarotLevel = abs($this->astrInfo['tarot_level']);
            $data[] = [
                'type' => 4,
                'title' => '问答-塔罗能力分',
                'img' => $imgHost . '/mini/astrologer/test/1.png',
                'grade' => $this->astrInfo['tarot_grade'],
                'level_name' => $astrModel->astrLevelName2[4][$tarotLevel],
                'proportion' => ($astrModel->getAstrQuestionAnswerProportion($nowTime, 3, $tarotLevel) * 100) . '%',
                'protocol_url' => $apiHost . '/web/rule_tarot_grade',
            ];
        } else
        {
            if ($hint)
            {
                $hint .= '、';
            }
            $hint .= '问答塔罗';
        }

        if ($hint !== '')
        {
            $hint = '你没有通过' . $hint . '考试认证，暂时没有相关能力分，快去前往考试吧～';
        }
        $res = [
            'list' => $data,
            'hint' => $hint,
        ];

        return show(200, '请求成功', $res);
    }

    /**
     * 能力分变动记录
     * @return Json
     * @throws DbException
     */
    public function getGradeChangeRecode()
    {
        $type = input('type/d', 1);

        if (!in_array($type, [1, 2, 4], true))
        {
            return show(config('code.error'), '请求异常，请稍后再试～');
        }
        $type = $type - 1;
        if ($type === 0)
        {
            $data = Db::table('wechat_backup_07_18_14_43_00.zlcr_astr_grade_change_recode')
                ->alias('r')->join('wechat_backup_07_18_14_43_00.zlcr_custom_report_question_comment c', 'r.qid=c.qid', 'left')
                ->where(['r.astr_id' => $this->astrInfo['id'], 'question_type' => $type])->order('id desc')
                ->field('r.qid,r.change,r.astro_grade,r.type,r.create_time,c.level')
                ->paginate()->toArray();
        } else
        {
            $data = Db::table('wechat_backup_07_18_14_43_00.zlcr_astr_grade_change_recode')
                ->alias('r')->join('wechat_backup_07_18_14_43_00.zlcr2_user_question_comment c', 'r.qid=c.qid', 'left')
                ->where(['r.astr_id' => $this->astrInfo['id'], 'question_type' => $type])->order('id desc')
                ->field('r.qid,r.change,r.astro_grade,r.type,r.create_time,c.level')
                ->paginate()->toArray();
        }


        $recodeData = [];
        foreach ($data['data'] as $recodeItem)
        {
            $cause = '';
            switch ($recodeItem['type'])
            {
                case 1:
                case 2:
                    $arr_n = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"];
                    $cause = $arr_n[$recodeItem['level']] . '星评价';
                    break;
                case 3:
                    $cause = '提交超时';
                    break;
                case 4:
                    $cause = '订单超时';
                    break;
                case 5:
                    $cause = '完成订单';
                    break;
                case 6:
                    $cause = '审核超限';
                    break;
                case 7:
                    $cause = '每日接单并回复对应问答5单';
                    break;
                case 8:     // 任务超时回复-5分
                    $cause = '问题回复超时';
                    break;
                case 9:     // 过去30天任务超时回复第2次-20分
                    $cause = '30天内2次回复超时';
                    break;
                case 10:    // 过去30天任务超时回复第3次-50分
                    $cause = '30天内3次回复超时';
                    break;
                case 11:    // 11=>追问回复超时
                    $cause = '追问回复超时';
                    break;
                case 12:    // 11=>追问回复超时
                    $cause = '30天内2次追问回复超时';
                    break;
                case 13:    // 11=>追问回复超时
                    $cause = '30天内3次追问回复超时';
                    break;

            }

            $recodeData[] = [
                'type' => in_array($recodeItem['type'], [1, 2], false) ? "用户评价" : "占星师行为",
                'qid' => $recodeItem['qid'],
                'change' => $recodeItem['change'],
                'astro_grade' => $recodeItem['astro_grade'], // 变动后星力值
                'cause' => $cause, // 原因
                'time' => date('Y-m-d H:i', $recodeItem['create_time'])
            ];
        }

        $data['data'] = $recodeData;
        return show(config('code.success'), '请求成功', $data);
    }
}
